/** 权限守卫 */
import type { Router, RouteRecordRaw } from 'vue-router'
import type { AppCodeType, LoadRouteType } from '../../enums'
import type { IMenu } from '../../store/menu'
import { Tree } from '@pkgs/utils'
import { camelCase, pick } from 'lodash-es'
import { MenuNodeType } from '../../enums'
import useAuthStore from '../../store/auth'
import useMenuStore from '../../store/menu'
import useMicroStore from '../../store/micro'
import { isFrontendLoadRoute } from '../../utils'

interface IParams {
  router: Router
  whitelist?: string[]
  loadRouteType: LoadRouteType
  appCode: AppCodeType
  getComponent?: (menu: IMenu) => any
}

let hasLoadDynamicRoute = false
const _whitelist = ['/login', '/404']

function addExtraRoutes(router: Router) {
  router.addRoute({
    path: '/login',
    name: 'login',
    component: () => import('../../pages/login/index.vue'),
  })

  router.addRoute({
    path: '/iframe/:pathMatch(.*)*',
    name: 'iframe',
    component: () => import('../../pages/iframe/index.vue'),
  })

  router.addRoute({
    path: '/:pathMatch(.*)*',
    name: '404',
    component: () => import('../../pages/404/index.vue'),
  })
}

export function createPermissionGuard({
  router,
  whitelist,
  loadRouteType,
  appCode,
  getComponent,
}: IParams) {
  router.beforeEach((to, from, next) => {
    addExtraRoutes(router)

    if ([..._whitelist, whitelist]?.includes(to.path)) {
      next()
      return
    }

    const authStore = useAuthStore()
    const microStore = useMicroStore()
    if (microStore.isMicro) {
      if (!microStore.getToken && to.name !== 'login') {
        next('/login')
        return
      }
    }
    else {
      if (!authStore.hasToken && to.name !== 'login') {
        next('/login')
        return
      }
    }

    if (isFrontendLoadRoute(loadRouteType) || hasLoadDynamicRoute) {
      next()
    }
    else {
      const { menus } = useMenuStore()
      new Tree<IMenu>().traversal(menus, (menu) => {
        if (menu.type === MenuNodeType.MENU) {
          const component = getComponent?.(menu)
          if (!component)
            return

          const route: RouteRecordRaw = {
            ...pick(menu, ['path', 'meta']),
            name: camelCase(`${appCode}${menu.path}`),
            component,
          }
          router.addRoute(route)
        }
      })

      hasLoadDynamicRoute = true
      next({ ...to, replace: true })
    }
  })
}
